package com.smart.community.region.service.impl;

import java.util.Collections;
import java.util.List;
import java.util.Arrays;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.enums.SystemStatusEnum;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.commons.utils.StringUtils;
import com.smart.community.feign.property.service.DataScopeFeign;
import com.smart.community.feign.user.dto.UserDTO;
import com.smart.community.feign.user.service.UserFeignService;
import com.smart.community.region.dto.ResidentAddDTO;
import com.smart.community.region.entity.Household;
import com.smart.community.region.entity.Resident;
import com.smart.community.region.entity.ResidentHousehold;
import com.smart.community.region.mapper.HouseholdMapper;
import com.smart.community.region.mapper.ResidentHouseholdMapper;
import com.smart.community.region.mapper.ResidentMapper;
import com.smart.community.region.service.IResidentService;
import com.smart.community.feign.user.dto.NormalUserCreateDTO;

import lombok.extern.slf4j.Slf4j;

/**
 * 住户信息服务实现类
 * 
 * @author Wu.Liang
 * @since 2025-07-28
 */
@Service
@Slf4j
public class ResidentServiceImpl extends ServiceImpl<ResidentMapper, Resident> implements IResidentService {
	@Autowired
    private HouseholdMapper householdMapper;
    @Autowired
    private ResidentHouseholdMapper residentHouseholdMapper;
    @Autowired
    private UserFeignService userFeignService;
    @Autowired
    private DataScopeFeign dataScopeFeign;
    
    @Override
    @Cacheable(value = "resident:user", key = "#userId")
    public List<Resident> getResidentsByUserId(Long userId) {
        long startTime = System.currentTimeMillis();
        log.info("根据用户ID查询住户信息，用户ID：{}", userId);
        
        try {
            if (userId == null) {
                log.warn("用户ID不能为空");
                return Collections.emptyList();
            }
            
            List<Resident> result = baseMapper.selectByUserId(userId);
            long endTime = System.currentTimeMillis();
            log.info("根据用户ID查询住户信息完成，查询到{}条记录，耗时{}ms", result.size(), endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("根据用户ID查询住户信息失败，耗时{}ms", endTime - startTime, e);
            return Collections.emptyList();
        }
    }
    
    @Override
    @Cacheable(value = "resident:name", key = "#realName")
    public List<Resident> getResidentsByRealName(String realName) {
        long startTime = System.currentTimeMillis();
        log.info("根据姓名模糊查询住户，姓名：{}", realName);
        
        try {
            if (StringUtils.isBlank(realName)) {
                log.warn("姓名不能为空");
                return Collections.emptyList();
            }
            
            List<Resident> result = baseMapper.selectByRealName(realName);
            long endTime = System.currentTimeMillis();
            log.info("根据姓名模糊查询住户完成，查询到{}条记录，耗时{}ms", result.size(), endTime - startTime);
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("根据姓名模糊查询住户失败，耗时{}ms", endTime - startTime, e);
            return Collections.emptyList();
        }
    }
    
    @Override
    @CacheEvict(value = {
        "resident:user", "resident:name", 
        "owner_household:owner", "owner_household:vos", "owner_household:household", 
        "owner_household:household_vos", "owner_household:household_ids", 
        "owner_household:owner_household", "owner_household:primary", 
        "owner_household:primary_households", "owner_household:exists", 
        "owner_household:page", "owner_household:vo",
        "owner:household", "owner_processing:association_exists",
        "household:page", "household:detail", "household:code", "household:feign:ids",
        "household:basicStats", "household:countByCommunity", "household:countByUnit",
        "datascope:householdIds", "datascope:householdPermission",
        "address"
    }, allEntries = true)
    public Resident addResidentWithPermission(ResidentAddDTO residentAddDTO) {
        long startTime = System.currentTimeMillis();
        log.info("新增住户信息（带权限验证），住户姓名：{}", residentAddDTO.getRealName());
        
        try {
            // 1. 参数校验
            validateAddResidentParams(residentAddDTO);
            
            // 2. 权限验证
            validateAddResidentPermission(residentAddDTO.getHouseholdId());
            
            // 3. 创建住户实体
            Resident resident = new Resident();
            BeanUtils.copyProperties(residentAddDTO, resident);
            
            // 4. 设置创建信息
            Long currentUserId = SecurityUtils.getCurrentUserId();
            if (currentUserId != null) {
                resident.setCreateBy(currentUserId);
                resident.setUpdateBy(currentUserId);
            }
            
            // 5. 处理用户关联逻辑
            Long associatedUserId = handleUserAssociation(residentAddDTO);
            if (associatedUserId != null) {
            	resident.setUserId(associatedUserId);
            	log.info("住户关联用户成功，住户ID：{}，用户ID：{}", resident.getId(), associatedUserId);
            } else {
            	log.warn("住户未关联用户账号，住户姓名：{}，手机号：{}，身份证号：{}", 
            		residentAddDTO.getRealName(), residentAddDTO.getPhone(), residentAddDTO.getIdentityNo());
            }
            
            // 6. 保存住户信息 
            boolean result = this.save(resident);
            if (!result) {
                log.error("新增住户信息失败，住户姓名：{}", residentAddDTO.getRealName());
                return null;
            }
            
            long endTime = System.currentTimeMillis();
            log.info("新增住户信息成功，住户ID：{}，关联用户ID：{}，耗时{}ms", resident.getId(), associatedUserId, endTime - startTime);
            
            // 7. 创建住户房户关联信息
            createResidentHouseholdAssociation(resident.getId(), residentAddDTO, currentUserId);
            
            return resident;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("新增住户信息失败，耗时{}ms", endTime - startTime, e);
            return null;
        }
    }
    
    /**
     * 参数校验
     */
    private void validateAddResidentParams(ResidentAddDTO residentAddDTO) {
        if (residentAddDTO.getRealName() == null || residentAddDTO.getRealName().trim().isEmpty()) {
            throw new BusinessException("住户姓名不能为空");
        }
        if (residentAddDTO.getIdentityNo() == null || residentAddDTO.getIdentityNo().trim().isEmpty()) {
            throw new BusinessException("身份证件号不能为空");
        }
        if (residentAddDTO.getHouseholdId() == null) {
            throw new BusinessException("房户ID不能为空");
        }
    }
    
    /**
     * 权限验证
     */
    private void validateAddResidentPermission(Long householdId) {
        try {
            Long currentUserId = SecurityUtils.getCurrentUserId();
            // 用户有权限管理的社区ID集合
            List<Long> userCommunityIds = dataScopeFeign.getUserCommunityIds(currentUserId);
            
            // 1. 检查超级管理员权限
            Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
            if (isSuperAdmin) {
                log.info("超级管理员新增住户，跳过权限验证");
                return;
            }
            
            // 2. 获取房户信息，验证用户是否有权限在该房户添加住户
            // 这里需要根据房户ID获取社区ID，然后验证用户是否有该社区的权限
            Household household = householdMapper.selectById(householdId);
            // 由于区域服务没有提供房户详情查询的Feign接口，这里暂时跳过社区权限验证
            if (household != null && userCommunityIds.contains(household.getCommunityId())) {
            	return;
            } else {
            	log.error("当前用户[id={}]无权限进行此房户的操作", currentUserId);
            	throw new BusinessException("创建新用户失败");
            }
            // 后续需要完善房户详情查询接口，实现完整的权限验证
            // 这里需要根据用户权限过滤房户数据
        } catch (Exception e) {
            log.error("权限验证失败", e);
            throw new BusinessException("权限验证失败");
        }
    }
    
    /**
     * 处理用户关联逻辑
     */
    private Long handleUserAssociation(ResidentAddDTO residentAddDTO) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        
        // 1. 首先根据身份证号查找用户
        if (residentAddDTO.getIdentityNo() != null && !residentAddDTO.getIdentityNo().trim().isEmpty()) {
            try {
                UserDTO userDTO = userFeignService.getUserByIdCard(residentAddDTO.getIdentityNo());
                if (userDTO != null) {
                    log.info("根据身份证号找到关联用户，用户ID：{}", userDTO.getId());
                    return userDTO.getId();
                }
            } catch (Exception e) {
                log.warn("根据身份证号查找用户失败，身份证号：{}，错误：{}", residentAddDTO.getIdentityNo(), e.getMessage());
            }
        }
        
        // 2. 如果根据身份证号没找到，尝试根据手机号查找用户
        if (residentAddDTO.getPhone() != null && !residentAddDTO.getPhone().trim().isEmpty()) {
            try {
                UserDTO userDTO = userFeignService.getUserByPhone(residentAddDTO.getPhone());
                if (userDTO != null) {
                    log.info("根据手机号找到关联用户，用户ID：{}", userDTO.getId());
                    
                    // 如果查手机号查到了用户信息，那么要把身份证号信息补上
                    if (residentAddDTO.getIdentityNo() != null && !residentAddDTO.getIdentityNo().trim().isEmpty()) {
                        try {
                            // 更新用户的身份证号信息
                            UserDTO updateUserDTO = new UserDTO();
                            updateUserDTO.setId(userDTO.getId());
                            updateUserDTO.setIdCard(residentAddDTO.getIdentityNo());
                            updateUserDTO.setRealName(residentAddDTO.getRealName());
                            updateUserDTO.setGender(residentAddDTO.getGender());
                            if (residentAddDTO.getBirthday() != null) {
                                updateUserDTO.setBirthday(residentAddDTO.getBirthday().toString());
                            }
                            updateUserDTO.setEmail(residentAddDTO.getEmail());
                            
                            Boolean updateResult = userFeignService.updateUser(updateUserDTO);
                            if (updateResult != null && updateResult) {
                                log.info("成功更新用户身份证号信息，用户ID：{}，身份证号：{}", userDTO.getId(), residentAddDTO.getIdentityNo());
                            } else {
                                log.error("更新用户身份证号信息失败，用户ID：{}，身份证号：{}", userDTO.getId(), residentAddDTO.getIdentityNo());
                                // 更新失败时记录错误，但不影响主流程
                            }
                        } catch (Exception updateException) {
                            log.error("更新用户身份证号信息时发生异常，用户ID：{}，身份证号：{}，错误：{}", 
                                userDTO.getId(), residentAddDTO.getIdentityNo(), updateException.getMessage(), updateException);
                            // 不抛出异常，避免影响主流程
                        }
                    }
                    
                    return userDTO.getId();
                }
            } catch (Exception e) {
                log.warn("根据手机号查找用户失败，手机号：{}，错误：{}", residentAddDTO.getPhone(), e.getMessage());
            }
        }
        
        // 3. 如果身份证号和手机号都查不到，创建新用户并填写完整信息
        // 修复：只有当手机号和身份证号都不为空时才创建新用户，且确保至少有一个不为空
        boolean hasPhone = residentAddDTO.getPhone() != null && !residentAddDTO.getPhone().trim().isEmpty();
        boolean hasIdCard = residentAddDTO.getIdentityNo() != null && !residentAddDTO.getIdentityNo().trim().isEmpty();
        
        if (hasPhone || hasIdCard) {
            try {
                log.info("未找到关联用户，开始创建新用户，姓名：{}，手机号：{}，身份证号：{}", 
                    residentAddDTO.getRealName(), residentAddDTO.getPhone(), residentAddDTO.getIdentityNo());
                
                // 创建NormalUserCreateDTO
                NormalUserCreateDTO createDTO = new NormalUserCreateDTO();
                createDTO.setRealName(residentAddDTO.getRealName());
                createDTO.setPhone(residentAddDTO.getPhone());
                createDTO.setIdCard(residentAddDTO.getIdentityNo());
                createDTO.setGender(residentAddDTO.getGender());
                if (residentAddDTO.getBirthday() != null) {
                    createDTO.setBirthday(residentAddDTO.getBirthday().toString());
                }
                createDTO.setEmail(residentAddDTO.getEmail());
                
                // 设置用户名（优先使用手机号，其次使用身份证号）
                if (hasPhone) {
                    createDTO.setUsername(residentAddDTO.getPhone());
                } else if (hasIdCard) {
                    createDTO.setUsername(residentAddDTO.getIdentityNo());
                } else {
                    // 如果都没有，使用姓名+时间戳
                    createDTO.setUsername(residentAddDTO.getRealName() + System.currentTimeMillis());
                }
                
                // 设置操作人ID（Feign接口规范要求显式传入）
                createDTO.setOperatorId(currentUserId);
                
                // 创建用户
                Long newUserId = userFeignService.createNormalUser(createDTO);
                if (newUserId != null) {
                    log.info("新用户创建成功，用户ID：{}", newUserId);
                    
                    // 4. 给新用户分配普通用户角色（ID=13）
                    try {
                        List<Long> roleIds = Arrays.asList(13L);
                        userFeignService.assignUserRoles(newUserId, roleIds);
                        log.info("已为新用户分配普通用户角色，用户ID：{}", newUserId);
                    } catch (Exception roleException) {
                        log.error("分配普通用户角色失败，用户ID：{}，错误：{}", newUserId, roleException.getMessage(), roleException);
                        // 角色分配失败不应该影响用户创建，但需要记录详细错误
                    }
                    
                    return newUserId;
                } else {
                    log.error("新用户创建失败，返回null，姓名：{}，手机号：{}", residentAddDTO.getRealName(), residentAddDTO.getPhone());
                }
            } catch (Exception createException) {
                log.error("创建新用户失败，姓名：{}，手机号：{}，身份证号：{}，错误：{}", 
                    residentAddDTO.getRealName(), residentAddDTO.getPhone(), residentAddDTO.getIdentityNo(), 
                    createException.getMessage(), createException);
                // 不抛出异常，避免影响主流程
            }
        } else {
            log.warn("无法创建新用户：手机号和身份证号都为空，姓名：{}", residentAddDTO.getRealName());
        }
        
        // 如果没有找到关联用户且创建失败，返回null
        log.warn("未找到关联用户且创建新用户失败，住户将不关联用户账号，姓名：{}", residentAddDTO.getRealName());
        return null;
    }
    
    /**
     * 创建住户房户关联信息
     * 注意：此方法在addResidentWithPermission中被调用，已通过@CacheEvict清除相关缓存
     */
    private void createResidentHouseholdAssociation(Long residentId, ResidentAddDTO residentAddDTO, Long currentUserId) {
        ResidentHousehold residentHousehold = new ResidentHousehold();
        residentHousehold.setResidentId(residentId);
        residentHousehold.setHouseholdId(residentAddDTO.getHouseholdId());
        residentHousehold.setResidentType(residentAddDTO.getResidentType() != null ? residentAddDTO.getResidentType() : 1); // 默认为户主
        residentHousehold.setMoveInDate(residentAddDTO.getMoveInDate());
        residentHousehold.setMoveOutDate(residentAddDTO.getMoveOutDate());
        residentHousehold.setContractStartDate(residentAddDTO.getContractStartDate());
        residentHousehold.setContractEndDate(residentAddDTO.getContractEndDate());
        residentHousehold.setMonthlyRent(residentAddDTO.getMonthlyRent());
        residentHousehold.setDeposit(residentAddDTO.getDeposit());
        residentHousehold.setContractNo(residentAddDTO.getContractNo());
        residentHousehold.setApplyStatus(SystemStatusEnum.ENABLED.getCode()); // 默认已通过
        residentHousehold.setStatus(SystemStatusEnum.ENABLED.getCode()); // 默认有效
        
        // 设置创建信息
        if (currentUserId != null) {
            residentHousehold.setCreateBy(currentUserId);
            residentHousehold.setUpdateBy(currentUserId);
        }
        
        // 保存住户房户关联信息
        boolean associationResult = residentHouseholdMapper.insert(residentHousehold) > 0;
        if (!associationResult) {
            throw new BusinessException("创建住户房户关联信息失败");
        }
        
        log.info("创建住户房户关联信息成功，关联ID：{}", residentHousehold.getId());
    }
} 